package ar.edu.unicen.pladema.main;

import java.util.List;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.Link;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;

import ar.edu.unicen.pladema.resources.JarResourse;
import ar.edu.unicen.pladema.resources.ResourceManager;


/**
 * Clase utilitaria para el manejo de funciones SWT muy utilizadas.
 *  
 * @author Sebastian Perruolo &lt;sperruolo[at]alumnos.exa.unicen.edu.ar&gt;
 */
public final class SWTUtils {
	/**
	 * Coordenada máxima para los {@link FormData}.
	 */
	public static final int MAX_FORMDATA_COORD = 100;
	
	/**
	 * Mitad de coordenada para los {@link FormData}.
	 */
	public static final int HALF_FORMDATA_COORD = 50;
	
	/**
	 * Margen izquierdo para los {@link FormData}.
	 */
	public static final int MARGIN_FORMDATA_LEFT = 5;
	
	/**
	 * Margen derecho para los {@link FormData}.
	 */
	public static final int MARGIN_FORMDATA_RIGHT = -5;
	
	/**
	 * Clases utilitarias no tienen creador.
	 */
	private SWTUtils() { }
	
	/**
	 * Crea un {@link Group} con el texto <i>text</i>.
	 * 
	 * @param parent Panel que contendrá al {@link Group}
	 * @param textKey Key del texto a mostrar
	 * @return un {@link Group} con el texto recibido.
	 */
	public static Group createGroup(final Composite parent, 
			final String textKey) {
		Group group = new Group(parent,  SWT.V_SCROLL | SWT.H_SCROLL);
		group.setText(ResourceManager.getInstance()
				.getText(textKey));
		group.setLayout(createFillLayout());
		group.setBackground(parent.getBackground());
		return group;
	}
	
	/**
	 * Crea un {@link FillLayout}.
	 * 
	 * @return un {@link FillLayout}
	 */
	public static Layout createFillLayout() {
		FillLayout layout = new FillLayout();
		layout.marginHeight = 2;
		layout.marginWidth = 2;
		return layout;
	}
	
	/**
	 * Crea un {@link FormData} utilizado en paneles que tienen
	 * {@link org.eclipse.swt.layout.FormLayout} seteado. Este 
	 * {@link FormData} ubica el componente al tope del padre.
	 * 
	 * @return un {@link FormData} que ubica al componente al tope del padre.
	 */
	public static FormData createTopFormData() {
		return createTopFormData(0);
	}
	
	/**
	 * Crea un {@link FormData} utilizado en paneles que tienen
	 * {@link org.eclipse.swt.layout.FormLayout} seteado. Este 
	 * {@link FormData} ubica el componente al tope del padre.
	 * 
	 * @param margin margen a utilizar
	 * @return un {@link FormData} que ubica al componente al tope del padre.
	 */
	public static FormData createTopFormData(final int margin) {
		FormData formData = new FormData();
		formData.left = new FormAttachment(0, margin);
		formData.top = new FormAttachment(0, margin);
		formData.right = new FormAttachment(MAX_FORMDATA_COORD, -margin);
		return formData;
	}
	
	
	
	/**
	 * Ubica el componente a la derecha.
	 * @return Un {@link FormData} que ubica el componente a la derecha.
	 */
	public static FormData createRightFormData(int margin) {
		FormData formData = new FormData();
		formData.top = new FormAttachment(0, margin);
		formData.right = new FormAttachment(MAX_FORMDATA_COORD, -margin);
		return formData;
	}
	
	
	/**
	 * Ubica el componente a la derecha.
	 * @return Un {@link FormData} que ubica el componente a la derecha.
	 */
	public static FormData createRightFormData(final Control control,
			int margin) {
		FormData formData = new FormData();
		formData.top = new FormAttachment(control, margin);
		formData.right = new FormAttachment(MAX_FORMDATA_COORD, -margin);
		return formData;
	}
	
	/**
	 * Retorna un {@link FormData} que ubica el control al que se le asigne
	 * debajo del control <code>control</code>.
	 * 
	 * @param control Control que estará ubicado arriba.
	 * @return un {@link FormData} para ubicar un control debajo del recibido
	 * 		por parámetro.
	 */
	public static FormData createBelowFormData(final Control control) {
		return createBelowFormData(control, 0);
	}
	
	/**
	 * Retorna un {@link FormData} que ubica el control al que se le asigne
	 * debajo del control <code>control</code>.
	 * 
	 * @param margin Margen a utilizar.
	 * @param control Control que estará ubicado arriba.
	 * @return un {@link FormData} para ubicar un control debajo del recibido
	 * 		por parámetro.
	 */
	public static FormData createBelowFormData(final Control control, 
			final int margin) {
		FormData formData = new FormData();
		formData.left = new FormAttachment(0, margin);
		formData.top = new FormAttachment(control, margin);
		formData.right = new FormAttachment(MAX_FORMDATA_COORD, -margin);
		return formData;
	}
	
	/**
	 * Retorna un {@link FormData} que ubica el control al que se le asigne
	 * debajo del control <code>control</code> y ocupando el resto del 
	 * espacio del panel.
	 * @param control Control que estará ubicado arriba.
	 * @return Ubicación al fondo y ocupando todo el área.
	 */
	public static FormData createFullBottomFormData(final Control control) {
		FormData formData = new FormData();
		formData.left = new FormAttachment(0, 0);
		formData.bottom = new FormAttachment(MAX_FORMDATA_COORD, 0);
		formData.top = new FormAttachment(control);
		formData.right = new FormAttachment(MAX_FORMDATA_COORD, 0);
		return formData;
	}
	
	/**
	 * Ubica el control al fondo, a la izquierda del control. Si control
	 * es null, ubica el control completamente a la derecha.
	 * Ideal para formularios donde los botones están a la derecha.
	 * 
	 * @param controlRight Control que estará ubicado a la derecha.
	 * @param controlTop Control que estará ubicado arriba.
	 * @param margin margen a utilizar.
	 * @return Ubicación al fondo y a la derecha.
	 */
	public static FormData createBottomRightFormData(final Control controlRight,
			final Control controlTop, final int margin) {
		FormData formData = new FormData();
		formData.bottom = new FormAttachment(MAX_FORMDATA_COORD, -margin);
		if (controlRight == null) {
			formData.right = new FormAttachment(MAX_FORMDATA_COORD, -margin);
		} else {
			formData.right = new FormAttachment(controlRight, -margin);
		}
		if (controlTop != null) {
			formData.top = new FormAttachment(controlTop, margin);
		}
		return formData;
	}
	
	public static FormData createBottomLeftFormData(final Control controlLeft,
			final Control controlTop, final int margin) {
		FormData formData = new FormData();
		formData.bottom = new FormAttachment(MAX_FORMDATA_COORD, -margin);
		if (controlLeft == null) {
			formData.left = new FormAttachment(0, margin);
		} else {
			formData.left = new FormAttachment(controlLeft, -margin);
		}
		if (controlTop != null) {
			formData.top = new FormAttachment(controlTop, margin);
		}
		return formData;
	}
	public static FormData createBottomFormData(final int margin) {
		FormData formData = new FormData();
		formData.left = new FormAttachment(0, margin);
		formData.right = new FormAttachment(MAX_FORMDATA_COORD, -margin);
		formData.bottom = new FormAttachment(MAX_FORMDATA_COORD, -margin);
		return formData;
	}
	
	/**
	 * Ubica el componente ocupando todo el lugar a la izquierda de
	 * {@link Control}.
	 * @param control Componente que estará a la derecha.
	 * @return Un {@link FormData} que ubica el componente a la izquierda
	 * 		del parametro.
	 */
	public static FormData createFullLeftFormData(final Control control) {
		FormData formData = new FormData();
		formData.left = new FormAttachment(0, 0);
		formData.top = new FormAttachment(0, 0);
		formData.right = new FormAttachment(control);
		return formData;
	}
	
	/**
	 * Convierte una lista de string en un array de string.
	 * @param list lista de string.
	 * @return array de string.
	 */
	public static String[] listToArray(final List<String> list) {
		String[] array = new String[list.size()];
		list.toArray(array);
		return array;
	}
	
	/**
	 * Convierte una lista de string en string separado por espacios.
	 * @param list lista de string.
	 * @return array de string.
	 */
	public static String listToString(final List<String> list) {
		StringBuffer result = new StringBuffer();
		for (String s : list) {
			result.append(s).append(" ");
		}
		return result.toString();
	}
	
	/**
	 * Crea un {@link Label} con una imagen en ella y con el evento
	 * especificado.
	 * 
	 * @param parent Control contenedor.
	 * @param keyImg key de la imagen.
	 * @param listener evento a disparar con el click.
	 * @return un label que simula un botón, pero mostrando un dibujito.
	 */
	public static Label createImageLabel(final Composite parent, 
			final String keyImg, final MouseListener listener) {
		Label label = new Label(parent, SWT.FLAT);
		label.setImage(
				JarResourse.getInstance().getResourceImage(parent.getDisplay(),keyImg)
			);
		
		if (listener != null) { //por las dudas, pero no tiene sentido
			label.addMouseListener(listener);
		}
		
		label.setToolTipText(ResourceManager.getInstance().getText(keyImg));
		return label;
	}
	/**
	 * Crea un botón. Los botones siempre se crear de la misma manera, además
	 * siempre disparan un evento.
	 * 
	 * @param parent Composite padre
	 * @param key clave del texto a mostrar
	 * @param listener listener a ejecutar
	 * @return un botón.
	 */
	public static Button createButton(final Composite parent, final String key, 
			final Listener listener) {
		Button aButton = new Button(parent, SWT.NONE);
		aButton.setText(ResourceManager.getInstance().getText(key));
		aButton.addListener(SWT.Selection, listener);
		return aButton;
	}
	
	/**
	 * Crea un link. Los links siempre se crear de la misma manera, además
	 * siempre disparan un evento.
	 * 
	 * @param parent Composite padre
	 * @param key clave del texto a mostrar
	 * @param listener listener a ejecutar
	 * @return un botón.
	 */
	public static Link createLink(final Composite parent, final String key, 
			final SelectionListener listener) {
		Link link = new Link(parent, 0);
		link.setText(ResourceManager.getInstance().getText(key));
		link.addSelectionListener(listener);
		//link.addListener(SWT.Selection, listener);
		return link;
	}
	
	/**
	 * Muestra un diálogo para que el usuario seleccione un directorio.
	 * 
	 * @param shell Shell de la aplicación
	 * @param textKey Clave del texto a mostrar
	 * @param messageKey Clave del mensaje a mostrar
	 * @param filterPath directorio original
	 * @return directorio elegido
	 */
	public static String getDirectoryFromUserDialog(final Shell shell, 
			final String textKey, final String messageKey, 
			final String filterPath) {
		//se crea el dialogo
		DirectoryDialog f = new DirectoryDialog(shell, SWT.OPEN);
		f.setText(
				ResourceManager.getInstance().getText(textKey)
			);
		f.setMessage(
				ResourceManager.getInstance()
				.getText(messageKey)
		);
		if (filterPath != null) {
			f.setFilterPath(filterPath);
		}
		//se muestra el dialogo
		return f.open();
	}
	
	/**
	 * Centra el Shell en la pantalla.
	 * @param shell Shell a centrar.
	 */
	public static void centerShell(final Shell shell) {
		Rectangle area = shell.getDisplay().getClientArea();
		Point size = shell.getSize();
		shell.setLocation(
				(area.width - size.x) / 2, 
				(area.height - size.y) / 2
			);
	}

	/**
	 * Cambia el estilo de la fuente del control.
	 * @param control Control a modificar.
	 * @param style Estilo nuevo.
	 */
	public static void changeStyle(final Control control, final int style) {
		FontData fd = control.getFont().getFontData()[0];
		fd.setStyle(style);
		control.setFont(new Font(control.getFont().getDevice(),
				fd
				));
	}


}
